/**
 * 
 */
package com.ms.service.module.baccarat.dm;

import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ms.game.gmtool.ServerShutdownType;
import com.ms.game.gmtool.message.SGmtoolKickAllConnectionNotify;
import com.ms.game.gmtool.message.SGmtoolServerShutdownCountdownNotify;
import com.ms.game.lobby.db.LobbyGameListWhileModel;
import com.ms.game.slot.base.DMAsyncHsitoryManger;
import com.ms.game.slot.base.SlotDMBasicServiceModule;
import com.ms.game.slot.base.SlotDmSeatHistoryBroadcastTimer;
import com.ms.game.slot.base.table.DMBasicTableUserInfo;
import com.ms.game.slot.base.table.DMBasicTableUserManager;
import com.ms.service.module.account.message.SCharacterLoginNotify;
import com.ms.service.module.baccarat.BacrTableOption;
import com.ms.service.module.baccarat.BacrUserInfo;
import com.ms.service.module.baccarat.bin.BacrMachineSetting;
import com.ms.service.module.baccarat.bin.BacrMachineSettingUtil;
import com.ms.service.module.baccarat.bin.BacrTableSettingInfo;
import com.ms.service.module.baccarat.db.BacrDAO;
import com.ms.service.module.baccarat.db.BacrMachineDataModel;
import com.ms.service.telnet.STelnetCmd;
import com.xpec.c4.game.datamanager.agent.PlayerDataAgent;
import com.xpec.c4.game.time.TimeSys;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.service.group.transportlayer.GroupMessage;
import com.xpec.c4.service.message.MessageAction;
import com.xpec.c4.service.module.ModuleName;
import com.xpec.c4.service.module.task.TaskTimer;

/**
 * @author TW15010
 *
 */
public class BacrDmModule extends SlotDMBasicServiceModule {
	
	private static final Log log = LogFactory.getLog(BacrDmModule.class);
	
	@Override
	public void procTelnetCommand(STelnetCmd obj) {
	}

	@Override
	public boolean startup() {
		SlotDmSeatHistoryBroadcastTimer broadcastTimer = new SlotDmSeatHistoryBroadcastTimer();
		broadcastTimer.setProcessor(getBasicprocesser());
		broadcastTimer.setInitialDelay(0);
		broadcastTimer.setPeriod(DMAsyncHsitoryManger.BROADCAST_TIMER_INTERVAL);
		broadcastTimer.setTimerOption(TaskTimer.LOOP);
		addTaskTimer(broadcastTimer);

		return super.startup();
	}

	@Override
	public void shutdown() {
		super.shutdown();
	}

	@Override
	public void init() {
		super.init();

		// message action
		registerActionClass(BacrDmAction.class);

		// model
		registerModelClass(BacrMachineDataModel.class);

		// 註冊use data center agent
		registerDCAgent(PlayerDataAgent.class);

		// 註冊主processer
		BacrDmProcessor proc = new BacrDmProcessor();
		proc.setModelName(this.getModelName());
		proc.setDMAsyncHsitoryMangerOwnModule(this);
		this.setBasicprocesser(proc);

		// 掃一遍機台設定，建立 tableId 轉 machineId 的 map
		HashMap<String, Integer> hallTypeToMachineIdMap = new HashMap<String, Integer>();
		ArrayList<BacrTableSettingInfo> tableList = BacrMachineSetting.getInstance().getTableList();
		int machineId = 1;
		for (BacrTableSettingInfo tableInfo : tableList) {
			hallTypeToMachineIdMap.put(tableInfo.getTableId(), machineId);
			machineId++;
		}
		proc.setHallTypeToMachineIdMap(hallTypeToMachineIdMap);
	}

	@Override
	public void onModuleServerReadyStart() {
		super.onModuleServerReadyStart();

		try {
			
			for (BacrTableSettingInfo info : BacrMachineSetting.getInstance().getTableList()) {
				String hallType = info.getTableId();
				int total = 1;
				String modelName = getModelName();
				Class<?> clazz = Class.forName(modelName);

				int nowcount = getMachineCount(clazz, hallType);

				// 新增
				if (total > nowcount) {
					Constructor<?> ctor = clazz.getConstructor();
					int machineid = nowcount + 1;

					for (int i = machineid; i <= total; i++) {
						Object obj = ctor.newInstance();
						initModelData(obj, hallType, i, BigDecimal.ONE);
						createGameMachine(obj);
					}
				}

				// 快取
				Object list = getMachineData(modelName, hallType, total);
				initCache(hallType, list);
			}
			
		} catch (Exception e) {
			if(log.isErrorEnabled()){
				log.error(GameUtility.getCurMethodName(), e);
			}
		}


		// 載入白名單, 之後會定時載入
		ArrayList<LobbyGameListWhileModel> whiteList = BacrDAO.loadWhiteList();
		BacrDmProcessor proc = (BacrDmProcessor) getBasicprocesser();
		proc.onLoadWhiteLis(whiteList);

		// 註冊定時載入白名單列表的計時器, 每分鐘一次
		BacrLoadWhiteListCronTask task = new BacrLoadWhiteListCronTask();
		task.setSrcModule(this);
		task.setCronExpressions("0 0/1 * * * ?");
		addCronTaskTimer(task);

		GroupMessage msg = new GroupMessage();
		msg.setMessageType(MessageTypes.S_BACR_DOORMAN_MACHINE_MODEL_READY);
		msg.setDestModuleID(ModuleName.BACR_GAME);
		MessageAction.sendGroupMessage(msg);
	}

	/**
	 * 設定model初始值
	 * 需@Override
	 * 
	 * @param model
	 */
	@Override
	public void initModelData(Object model, String halltype, int machineid, BigDecimal gainRate) {
		BacrMachineDataModel m = (BacrMachineDataModel) model;

		m.setHalltype(halltype);
		m.setMachineid(machineid);
		m.setModify_time(GameUtility.longToDate(TimeSys.currentTimeMills()));
	}
	
	/**
	 * 設定快取資料初始值
	 * 需@Override
	 * @param model
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void initCache(String halltype , Object list)
	{
		List<BacrMachineDataModel> mlist = castObjToList(list);
		
		BacrTableSettingInfo setter = BacrMachineSettingUtil.getTableSetting(halltype);
		DMBasicTableUserManager<BacrUserInfo, BacrTableOption> seatinfo = ((BacrDmProcessor)this.getBasicprocesser()).getSeatinfo();
		
		for(BacrMachineDataModel model:mlist)
		{
			BacrTableOption option = new BacrTableOption();
			DMBasicTableUserInfo<BacrUserInfo, BacrTableOption> data = new DMBasicTableUserInfo<BacrUserInfo, BacrTableOption>();
			
			option.halltype = halltype;
			option.isTrial =setter.isTrial();
			option.maxUser = setter.getMaxPlayer();
			
			data.setMaxUser(option.maxUser);
			data.setOption(option);
			
			HashMap<String,DMBasicTableUserInfo<BacrUserInfo, BacrTableOption>> cardtable = seatinfo.getTable();
			cardtable.put(halltype, data);
			
			BacrDmProcessor proc = (BacrDmProcessor) getBasicprocesser();
			proc.initFromMachineModel(model);
		}
		
	}

	@Override
	public void onPlayerLoginGameNotify(SCharacterLoginNotify notify) {
		BacrDmProcessor proc = (BacrDmProcessor) getBasicprocesser();
		proc.onPlayerLoginGameNotify(notify);
	}
	
	@Override
	public void onRecvServerShutdownCountdownNotify(SGmtoolServerShutdownCountdownNotify notify) {

		super.onRecvServerShutdownCountdownNotify(notify);
		if (notify.getShutdownType() != ServerShutdownType.Single_Game) {// 不是單一維護，就不用做
			return;
		}
		
		BacrDmProcessor proc = (BacrDmProcessor) this.getBasicprocesser();
		if(proc == null){
			return;
		}
		
		proc.onRecvServerShutdownCountdownNotify(notify);
		
	}

	@Override
	public void onRecvKickAllConnectionNotify(SGmtoolKickAllConnectionNotify request) {
		super.onRecvKickAllConnectionNotify(request);
		
		if (request.getShutdownType() != ServerShutdownType.Single_Game) { // 不是單一維護，就不用做
			return;
		}
		
		BacrDmProcessor proc = (BacrDmProcessor) this.getBasicprocesser();
		if(proc == null){
			return;
		}
		
		proc.onRecvKickAllConnectionNotify();
	}
}
